﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Hi_Baidu.User.Serializable.Log;
using Hi_Baidu.Packet.InPacket.TalkInPacket.Hole;
using Hi_Baidu.Entry.CollectionObject;
using Hi_Baidu.Enum.DigHole;

namespace Hi_Baidu.ProcessModel
{
    class ClientProcessModel : Model
    {
        private static String DIR_APP_USER = "../Users/AllUsers/";
        private static String FILE_APP_USER = "../Users/AllUsers/AppUser.db";

        /// <summary>
        ///     创建当前客户端应用程序用户统计目录
        /// </summary>
        public static void CreateClientUserRoot()
        {
            if(!CheckClientUserRoot())
            {
                Directory.CreateDirectory("../Users/AllUsers/");
            }
        }

        /// <summary>
        ///     创建当前客户端应用程序用户统计文件
        /// </summary>
        public static void CreateClientUserFile()
        {
            if (!CheckClientUserFile())
            {
                Globle.applicationUserManager = new Hi_Baidu.User.Serializable.Log.ApplicationUserManager(FILE_APP_USER, "APPLICATION_TOTAL_USER_INFO");
                Globle.applicationUserManager.Save(FILE_APP_USER);
            }
        }

        /// <summary>
        ///     检测当前客户端应用程序用户统计目录是否存在
        /// </summary>
        /// <returns>
        ///     返回false , 则表示不存在
        /// </returns>
        public static bool CheckClientUserRoot()
        {
            if (!Directory.Exists(DIR_APP_USER))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        ///     检测当前客户端应用程序用户统计文件是否存在
        /// </summary>
        /// <returns>
        ///     返回false , 则表示不存在
        /// </returns>
        public static bool CheckClientUserFile()
        {
            //如果不存在，则建立文件夹
            if (!File.Exists(FILE_APP_USER))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        ///     得到全局用户统计数据
        /// </summary>
        public static void GetApplicationUser()
        {
            using (FileStream FS = new FileStream(FILE_APP_USER, FileMode.Open))
            {
                using(MemoryStream MS = new MemoryStream())
                {
                    //byte[] EncryptData = new byte[FS.Length];
                    BinaryReader BR = new BinaryReader(FS);
                    byte[] EncryptData = BR.ReadBytes((int)FS.Length);
                    //BR.Read(EncryptData, 0, EncryptData.Length);
                    MS.Write(EncryptData, 0, EncryptData.Length);
                    MS.Position = 0;
                    ApplicationUserManager applicationUserManager = new ApplicationUserManager(MS, "APPLICATION_TOTAL_USER_INFO");
                    Globle.applicationUserManager = (ApplicationUserManager)applicationUserManager.DeEncryptStream;
                }
            }
        }

        /// <summary>
        ///     保存当前全局用户资料
        /// </summary>
        public static void SaveApplicationUser()
        {
            Globle.applicationUserManager.Save(FILE_APP_USER);
        }

        /// <summary>
        ///     返回全局用户资料
        /// </summary>
        public static List<IMetaData> ReadApplicationUserInfo()
        {
            if(Globle.applicationUserManager != null)
            {
                return Globle.applicationUserManager.GetMember();
            }
            return null;
        }

        ///// <summary>
        /////     向指定在线好友发送对于指定端口的打洞请求包
        ///// </summary>
        ///// <param name="username" type="byte[]">
        /////     <para>
        /////         自身用户名
        /////     </para>
        ///// </param>
        ///// <param name="Friendname" type="byte[]">
        /////     <para>
        /////         好友用户名
        /////     </para>
        ///// </param>
        ///// <param name="HolePort" type="byte[]">
        /////     <para>
        /////         打洞端口
        /////     </para>
        ///// </param>
        ///// <param name="digType" type="DigType">
        /////     <para>
        /////         打洞类型
        /////     </para>
        ///// </param>
        //public static void DigHole(byte[] username, byte[] Friendname, byte[] HolePort, DigType digType)
        //{
        //    byte[] UsernameLength = BitConverter.GetBytes(username.Length);
        //    byte[] FriendnameLength = BitConverter.GetBytes(Friendname.Length);
        //    byte[] packagebody = new byte[username.Length + Friendname.Length + 16];
        //    Offset = 0;
        //    Array.ConstrainedCopy(UsernameLength, 0, packagebody, Offset, 4);
        //    Offset += 4;
        //    Array.ConstrainedCopy(username, 0, packagebody, Offset, username.Length);
        //    Offset += username.Length;
        //    Array.ConstrainedCopy(FriendnameLength, 0, packagebody, Offset, 4);
        //    Offset += 4;
        //    Array.ConstrainedCopy(Friendname, 0, packagebody, Offset, Friendname.Length);
        //    Offset += Friendname.Length;
        //    Array.ConstrainedCopy(HolePort, 0, packagebody, Offset, 4);
        //    Offset += 4;
        //    Array.ConstrainedCopy(BitConverter.GetBytes((int)digType), 0, packagebody, Offset, 4);
        //    Offset += 4;
        //    byte[] protocol1 = ProtocolFactory.ProtocolFactory.ReGetProtocolToTalkMessage("DigHole",
        //                                                               (int)Packet.Protocol.TALK_OUT_NetworkCommand.DIG_A_HOLE,
        //                                                               (int)Packet.Protocol.NetworkProtocol.TALK_MESSAGE,
        //                                                               packagebody,
        //                                                               ProtocolFactory.ProtocolFactory.ACK.Yes,
        //                                                               ProtocolFactory.ProtocolFactory.ENCRYPT.No,
        //                                                               Globle.user.SESSION_CODE);
        //    NetControl.Send(protocol1, 8700, ServerIp);
        //}

        /// <summary>
        ///     处理转发的打洞申请
        /// </summary>
        /// <param name="inpackage" type="Hi_Baidu.Packet.InPacket.TalkInPacket.Hole.RedirectHolePacket">
        ///     <para>
        ///         转发的打洞申请请求包
        ///     </para>
        /// </param>
        public static void Process_RedirectHole(RedirectHolePacket inpackage)
        {
            Friend friend = Globle.friendCollection.GetMemberByKey(inpackage.GetUsername()) as Friend;
            if (friend != null & friend.OnlineState)
            {
                //发送测试信息
                byte[] UsernameLength = BitConverter.GetBytes(Globle.user.DIC_USERINFO["USERNAME"].Length);
                byte[] packagebody = new byte[Globle.user.DIC_USERINFO["USERNAME"].Length + 12];
                Offset = 0;
                Array.ConstrainedCopy(UsernameLength, 0, packagebody, Offset, 4);
                Offset += 4;
                Array.ConstrainedCopy(Globle.user.DIC_USERINFO["USERNAME"], 0, packagebody, Offset, Globle.user.DIC_USERINFO["USERNAME"].Length);
                Offset += Globle.user.DIC_USERINFO["USERNAME"].Length;
                byte[] HolePort = BitConverter.GetBytes(inpackage.GetHolePort());
                Array.ConstrainedCopy(HolePort, 0, packagebody, Offset, 4);
                Offset += 4;
                Array.ConstrainedCopy(inpackage.GetDigType(), 0, packagebody, Offset, 4);
                Offset += 4;
                byte[] protocol1 = ProtocolFactory.ProtocolFactory.ReGetProtocolToTalkMessage("TestDigHole",
                                                                       (int)Packet.Protocol.TALK_OUT_NetworkCommand.TEST_HOLE,
                                                                       (int)Packet.Protocol.NetworkProtocol.TALK_MESSAGE,
                                                                       packagebody,
                                                                       ProtocolFactory.ProtocolFactory.ACK.Yes,
                                                                       ProtocolFactory.ProtocolFactory.ENCRYPT.No,
                                                                       Globle.user.SESSION_CODE);
                NetControl.Send(protocol1, inpackage.GetHolePort(), friend.IpAddress);
                //向服务器发送打洞测试回馈
                byte[] username = Encoding.Default.GetBytes(inpackage.GetUsername());
                UsernameLength = BitConverter.GetBytes(username.Length);
                byte[] Friendname = Globle.user.DIC_USERINFO["USERNAME"];
                byte[] FriendnameLength = BitConverter.GetBytes(Friendname.Length);
                packagebody = new byte[username.Length + Friendname.Length + 16];
                Offset = 0;
                Array.ConstrainedCopy(UsernameLength, 0, packagebody, Offset, 4);
                Offset += 4;
                Array.ConstrainedCopy(username, 0, packagebody, Offset, username.Length);
                Offset += username.Length;
                Array.ConstrainedCopy(FriendnameLength, 0, packagebody, Offset, 4);
                Offset += 4;
                Array.ConstrainedCopy(Friendname, 0, packagebody, Offset, Friendname.Length);
                Offset += Friendname.Length;
                Array.ConstrainedCopy(HolePort, 0, packagebody, Offset, 4);
                Offset += 4;
                Array.ConstrainedCopy(inpackage.GetDigType(), 0, packagebody, Offset, 4);
                Offset += 4;
                protocol1 = ProtocolFactory.ProtocolFactory.ReGetProtocolToTalkMessage("AckDigHole",
                                                                       (int)Packet.Protocol.TALK_OUT_NetworkCommand.ACK_HOLE,
                                                                       (int)Packet.Protocol.NetworkProtocol.TALK_MESSAGE,
                                                                       packagebody,
                                                                       ProtocolFactory.ProtocolFactory.ACK.Yes,
                                                                       ProtocolFactory.ProtocolFactory.ENCRYPT.No,
                                                                       Globle.user.SESSION_CODE);
                NetControl.Send(protocol1, 8700, ServerIp);
            }
        }

        /// <summary>
        ///     处理好友的打洞测试
        /// </summary>
        /// <param name="inpackage" type="Hi_Baidu.Packet.InPacket.TalkInPacket.Hole.TestHolePacket">
        ///     <para>
        ///         打洞测试请求包
        ///     </para>
        /// </param>
        public static void Process_TestHole(TestHolePacket inpackage)
        {
            Friend friend = Globle.friendCollection.GetMemberByKey(inpackage.GetUsername()) as Friend;
            if(friend != null && friend.OnlineState)
            {
                switch ((DigType)BitConverter.ToInt32(inpackage.GetDigType(), 0))
                {
                    case DigType.TALK:
                        friend.HasTalkPortHole = true;
                        break;
                    case DigType.FILE_TRANSFER:
                        friend.HasFilePortHole = true;
                        break;
                    case DigType.VIDEO:
                        friend.HasVideoPortHole = true;
                        break;
                    case DigType.VOICE:
                        friend.HasVoicePortHole = true;
                        break;
                    default:
                        break;
                }
            }
        }

        /// <summary>
        ///     处理服务器发送的打洞反馈
        /// </summary>
        /// <param name="inpackage" type="Hi_Baidu.Packet.InPacket.TalkInPacket.Hole.AckServerHolePacket">
        ///     <para>
        ///         服务器打洞反馈请求包
        ///     </para>
        /// </param>
        public static void ProcessAckServerHole(AckServerHolePacket inpackage)
        {
            Friend friend = Globle.friendCollection.GetMemberByKey(inpackage.GetFriendUsername()) as Friend;
            if(friend != null && friend.OnlineState)
            {
                switch ((DigType)BitConverter.ToInt32(inpackage.GetDigType(), 0))
                {
                    case DigType.TALK:
                        friend.HasTalkPortHole = true;
                        break;
                    case DigType.FILE_TRANSFER:
                        friend.HasFilePortHole = true;
                        break;
                    case DigType.VIDEO:
                        friend.HasVideoPortHole = true;
                        break;
                    case DigType.VOICE:
                        friend.HasVoicePortHole = true;
                        break;
                    default:
                        break;
                }
            }
        }
    }
}
